/**
 * @file main.c
 * @brief COSC361 - MCU Jukebox Project \n
 * Group: Hamish Cumming, Brian Thorne \n
 * Latest source can be obtained using SVN from google's code repository with the following command:\n
 * svn checkout http://mega8-hob.googlecode.com/svn/trunk/ jukebox-hamish-brian\n
 * Description: The main controlling module, initialises all other modules and determains program flow\n
 * Date: 25/5/2008\n
 */

#include "Board.h"
#include "spi.h"
#include "tone.h"
#include "display.h"
#include "keypad.h"
#include "timer.h"
#include "player.h"

/* Function Prototypes */
static int wait ( int loops );
static void process_keypad(void);
static void enableRedLED(void);
static void disableRedLED(void);
static void enableGreenLED(void);
static void disableGreenLED(void);
static int buttonFromCode(int code);
void reset_time(void); //called in player

/* File variables */
static unsigned int LedSpeed = MCKKHz/600;
static unsigned int time1 = 0; //this increments over every 1.4 seconds (max value of timer1)
static unsigned int time2 = 0; //this holds the current amount of time since the last time1 update

/**
 * @brief Entry point
 */
int main(void)
{
    // First, enable the clock of the PIO
    AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1 << AT91C_ID_PIOA ) ;
    AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, STATUS_LED_RED | STATUS_LED_GREEN); //the status LEDs
    
    /* initialise each module */
    display_init();
    SPI_init();
    keypad_init();
    timer0_init();
    timer1_init();
    
    int curdigit = 0;
    /* Loop forever */
    for (;;)
    {
        /*Scan the keypad for any button presses and take action.*/
        process_keypad();   
        /* Output the music */
        if(player_isPlaying())
        {
            player_step(time1+time2);//play the notes
            /* Show the time in seconds */
            if (timer1_overflow()) time1 += 140;
            time2 = timer1_getCurrentValue()*140/0xFFFF;
            displayTime((time1 + time2)/100);
            enableGreenLED();
            disableRedLED();
        }
        else if (player_isIdle())
        {
            time1=time2=0;
            disableGreenLED();
            enableRedLED();
        }

        /* Refresh led display */
        if (wait(LedSpeed)) led_update(curdigit++);
        if (curdigit > NUM_DIGITS) curdigit = 0;
    }
}

/**
 * @brief Converts the raw button input to a number
 * @return A number (0-15) corresponding to the key pressed
 */
static int buttonFromCode(int code)
{
    int i;
    for(i=0;i<16;i++)
    {
        if(keymap[i]==code) return i;
    }
    return 0;
}

/**
 * @brief Processes any keypad input
 */
static void process_keypad(void)
{
    unsigned int keypad_input = keypad_getKeys();
    unsigned int button = buttonFromCode(keypad_input);
    static void (*funcArray[6])(void) = {&player_previous,&player_next,&player_volumeDown,&player_volumeUp,&player_stop, &player_play_pause};
    
    if(keypad_input) //Only do this if a button has actually been pressed!
    {    
        if(button>=10)
        {
            funcArray[button-10]();
        } else {
            player_chooseSong(button);
        }
    }
}

/**
 * @brief Reset the time (called when a song stops)
 */
void reset_time(void)
{
    time1 = time2 = 0;
    displayTime(0);
    enableRedLED();
    disableGreenLED();
}

/**
 * @brief A Waiting loop
 * @param loops The number of iterations to do before returning true
 * @return True if the function has been called loops times, false otherwise
 */
static int wait ( int loops )
{
    volatile static unsigned int waiting_time = 0;
    waiting_time++;
    if (waiting_time >= loops){
        waiting_time = 0;
        return 1;
    }
    else
        return 0;
}

/**
 * @brief Enables the Red Status LED
 */
static void enableRedLED()
{
    AT91F_PIO_SetOutput( AT91C_BASE_PIOA, STATUS_LED_RED);
}

/**
 * @brief Disables the Red Status LED
 */
static void disableRedLED()
{
    AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, STATUS_LED_RED);
}

/**
 * @brief Enables the Green Status LED
 */
static void enableGreenLED()
{
    AT91F_PIO_SetOutput( AT91C_BASE_PIOA, STATUS_LED_GREEN);
}

/**
 * @brief Disables the Green Status LED
 */
static void disableGreenLED()
{
    AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, STATUS_LED_GREEN);
}
